package com.podhradie.net.themperature.tools;

import java.awt.TextArea;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;

public class Context {
	
	public enum LogCategory {
		SYSTEM, CLIENT, UDP_SERVER, PROPERTY;
		public static String getLogCategory (LogCategory logCategory){
			switch (logCategory) {
			case SYSTEM:
				return "SYS";
			case CLIENT:
				return "CLT";
			case UDP_SERVER:
				return "USR";
			case PROPERTY:
				return "PRO";
			default:
				return "UND";
			}
		}
	}

	private static Context instance;

	private static final int MAX_OUTLINE_COUNT = 2000;
	private static final int A_TEMPERATURE_SIZE = 6;
	
	private double temperature;
	private double aTemperature;
	private String timeStamp;
	private boolean isConnected;
	private boolean udpListening;
	private TextArea outLine;
	private ArrayList<String> outLineBuffer;
	private ArrayList<Double> aTemperatureValues;
	

	private PropertyChangeSupport contextChange;
	
	private Context (){
		 setTemperatureChange(new PropertyChangeSupport(this));
		 outLineBuffer = new ArrayList<String>();
		 aTemperatureValues  = new ArrayList<Double>();
		 aTemperature = -1000;
	}

	public static Context get() {
		if (instance == null) {
			return instance = new Context();
		} else {

			return instance;
		}

	}

	public synchronized void addContextChangeListener(PropertyChangeListener l) {
		getContextChange().addPropertyChangeListener(l);
	}

	public synchronized void removeContextChangeListener(PropertyChangeListener l) {
		getContextChange().removePropertyChangeListener(l);
	}

	/**
	 * @return the temperature
	 */
	public double getTemperature() {
		return temperature;
	}

	/**
	 * @param temperature
	 *            the temperature to set
	 */
	public void setTemperature(double temperature) {
		double oldValue = this.temperature;
		this.temperature = temperature;
		getContextChange().firePropertyChange("temperature", oldValue,temperature);
		addaTemperatureValue(temperature);
		//Context.get().printLine(LogCategory.CLIENT,"fire temperature change " + oldValue + " "+ temperature);
	}

	/**
	 * @return the timeStamp
	 */
	public String getTimeStamp() {
		return timeStamp;
	}

	/**
	 * @param timeStamp
	 *            the timeStamp to set
	 */
	public void setTimeStamp(String timeStamp) {
		String oldValue = this.timeStamp;
		this.timeStamp = timeStamp;
		getContextChange().firePropertyChange("timeStamp", oldValue,timeStamp);
	}

	/**
	 * @return the contextChange
	 */
	public PropertyChangeSupport getContextChange() {
		return contextChange;
	}

	/**
	 * @param contextChange the contextChange to set
	 */
	public void setTemperatureChange(PropertyChangeSupport temperatureChange) {
		this.contextChange = temperatureChange;
	}

	/**
	 * @return the isConnected
	 */
	public boolean isConnected() {
		return isConnected;
	}

	/**
	 * @param isConnected the isConnected to set
	 */
	public void setConnected(boolean isConnected) {
		boolean oldValue = this.isConnected;
		this.isConnected = isConnected;
		getContextChange().firePropertyChange("isConnected", oldValue, isConnected);
	}

	/**
	 * @param outLine the outLine to set
	 */
	public void setOutLine(TextArea outLine) {
		this.outLine = outLine;
	}
	
	/**
	 * @return the aTemperature
	 */
	public double getaTemperature() {
		return aTemperature;
	}

	/**
	 * @param aTemperature the aTemperature to set
	 */
	public void setaTemperature(double aTemperature) {
		double oldValue = this.aTemperature;
		this.aTemperature = aTemperature;
		getContextChange().firePropertyChange("aTemperature", oldValue, aTemperature);
	}
	
	private void addaTemperatureValue (double value){
		aTemperatureValues.add(value);
		if (aTemperatureValues.size()==A_TEMPERATURE_SIZE){
			double sum = 0;
			Iterator<Double> iterator = aTemperatureValues.iterator();
			while (iterator.hasNext()) {
				double currentValue = iterator.next();
				sum = sum + currentValue;
			}
			BigDecimal bd = new BigDecimal(sum/aTemperatureValues.size());
		    bd = bd.setScale(1,BigDecimal.ROUND_HALF_UP);
			setaTemperature(bd.doubleValue());
			aTemperatureValues.clear();
		}
		
	}
	
	/**
	 * @return the udpListening
	 */
	public boolean isUdpListening() {
		return udpListening;
	}

	/**
	 * @param udpListening the udpListening to set
	 */
	public void setUdpListening(boolean udpListening) {
		boolean oldValue = this.isUdpListening();
		this.udpListening = udpListening;
		getContextChange().firePropertyChange("udpListening", oldValue, udpListening);
	}

	public void printLine (LogCategory destination, String line){
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM/HH:mm:ss");
		String dateAsString = simpleDateFormat.format(new Date());
		if (outLine !=null){
			outLineBuffer.add(dateAsString+"#"+ LogCategory.getLogCategory(destination) + "#" + line);
		}
		outLine.setText("");
		String outLineText = "";
		if (outLineBuffer.size() == MAX_OUTLINE_COUNT)outLineBuffer.remove(0);
		for (int i = outLineBuffer.size()-1; i > -1 ; i--){
			outLineText +=outLineBuffer.get(i)+"\n";
		}
		outLine.setText(outLineText);
	
	}


}
